#include <iostream>
#include "mgr/WorkerMgr.h"
#include "lib_json/json.h"
#include "tool/Utility.h"
#include "tool/Proto.h"
#include "mgr/LogMgr.h"
#include "mgr/HttpMgr.h"
#include "mgr/MsgSender.h"
#include <algorithm>
#include "hv/hbase.h"
#include "hv/requests.h"


int WorkerMgr::Init(const std::string& conf_file) {
	Json::Value root;
	if (!Utility::LoadJson(conf_file, root)) return -1;
	this->m_interval = root["interval"].asInt();
#ifdef _WIN32
	WSADATA  wsaData;
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
		std::cout << "WSAStartup Fail:" << GetLastError() << std::endl;
		return 1;
	}
#endif
	// 可能还需要设定 cuda使用第二张显卡
	
	return 0;
}

std::shared_ptr<CameraInfo> WorkerMgr::GetCameraInfo(int id){
	auto iter = this->m_cameras.find(id);
	if(iter != this->m_cameras.end())
	{
	 	return iter->second;
	}
	return nullptr;
}

std::shared_ptr<TaskInfo> WorkerMgr::GetTaskInfo(int type, int id)
{
	auto iter = this->m_tasks.find(std::make_pair(type, id));
	if(iter != this->m_tasks.end())
	{
	 	return iter->second;
	}
	return nullptr;
}

void WorkerMgr::Run() {
	m_thread = std::thread(&WorkerMgr::_Run, this);
}

void WorkerMgr::_Run() {

	// 登录一下 
	// HttpMgr::instance().ReqLogin();
	// // 处理 相机
	// this->SyncCamList();
	// // 处理 任务
	// this->SyncTaskList();
	// // 处理 技战任务
	// this->SyncSkillList();
	// // 理论上主要的东西都有了 然后就是 根据任务的变化 再给相机信息进行变动的处理了
	// this->DoUpdate();

	// // TESTTTTTT 静态配置测试
	// Json::Value root;
	// Utility::LoadJson("./config/config_worker.json", root);
	// const Json::Value& cams = root["cams"];
	// std::vector<int> allCameIds;
	// for(unsigned int t = 0; t < cams.size();t++){
	// 	std::string url = cams[t].asString();
	// 	std::shared_ptr<CameraInfo> pCamera = std::make_shared<CameraInfo>();
	// 	pCamera->dirty_sync = true;
	// 	pCamera->dirty_worker = true;
	// 	this->m_cameras[t] = pCamera;

	// 	LOG_INFO("Camera New " << t)
	// 	pCamera->id = t;
	// 	pCamera->type = 0;
	// 	pCamera->enable = 1;
	// 	pCamera->url = url;
	// 	pCamera->srois = "";
	// 	pCamera->location = "Test Location";

	// 	allCameIds.push_back(t);
	// }

	// std::shared_ptr<TaskInfo> pTask = std::make_shared<TaskInfo>();
	// pTask->dirty_cams = true;
	// this->m_tasks[1] = pTask;
	// LOG_INFO("Task New " << 1)
	// pTask->id = 1;
	// pTask->stypes = "1";
	// std::vector<int> _types;
	// _types.push_back(1);
	// pTask->types = _types;
	// pTask->scams = "";
	// pTask->cams = allCameIds;
	// pTask->name = "Test Task";

	// this->DoUpdate();
	// int round = 0;
	while (!m_exit)
	{	

		// 处理 相机
		this->SyncCamList();
		// 处理 任务
		this->SyncTaskList();
		// 处理 技战任务
		this->SyncSkillList();
		// 理论上主要的东西都有了 然后就是 根据任务的变化 再给相机信息进行变动的处理了
		this->DoUpdate();


		this->DoHttpMsg();
		// 真正意义上的轮询制度?? 一批20个 试试看 直接每次都进行创建和销毁好了 不然真的很麻烦
		// 算法服务器速度当作是 1s 10路 我这边控制速度!
		// 如果100路 60s 就是 5s 10路 就ok了 试试看这里轮询感觉一下
		// if(m_queue.empty()){
		// 	m_queue.reserve(m_cameras.size());
		// 	std::for_each(m_cameras.begin(), m_cameras.end(),
        //          [this](const std::map<int, std::shared_ptr<CameraInfo>>::value_type& p) 
        //          { this->m_queue.push_back(p.first); });
		// 	round++;
		// }
		// // 上一波执行完 执行下一波
		// if(m_workers.size() == 0){
		// 	int index = round % 10;
		// 	size_t batchnum = 20;
		// 	if(m_queue.size() < batchnum){
		// 		batchnum = m_queue.size();
		// 	}
		// 	for (size_t i = 0; i < batchnum; i++)
		// 	{
		// 		std::shared_ptr<CameraInfo> pCamera = GetCameraInfo(m_queue[i]);
		// 		if(pCamera == nullptr || !pCamera->enable || pCamera->tasks.size() == 0) continue;
		// 		std::shared_ptr<Worker> pWorker = std::make_shared<Worker>(pCamera->id, this->m_interval, pCamera->url);
		// 		pWorker->Run_OneFrame(index);
		// 		m_workers.push_back(pWorker);
		// 	}
		// 	m_queue.erase(m_queue.begin(), m_queue.begin() + batchnum);
		// 	LOG_INFO("Queue count: " << index << "||" << m_queue.size());
		// }
		

		
		// 每10s去Load一次试试看 不过现在可以暂时不管就是了
		m_workers.erase(std::remove_if(m_workers.begin(), m_workers.end(), [](std::shared_ptr<Worker> t) { return t->IsStop();}), m_workers.end());
		// LOG_INFO("Workers count: " << m_workers.size());
		// 10s动一次应该够了
		std::this_thread::sleep_for(std::chrono::milliseconds(10000));
	}
}

// 拉取相机信息
void WorkerMgr::SyncCamList(){
	Json::Value root_device;
	if (!HttpMgr::instance().ReqDeviceList(root_device) || root_device["code"] != 0)
	{
		// 获取不到 直接离开
		return;
	}

	for (auto& it:m_cameras)
	{
		it.second->dirty_remove = true;
	}
	
	// 遍历
	for (size_t i = 0; i < root_device["data"].size(); i++)
	{
		const Json::Value& data = root_device["data"][(int)i];
		int cam_id = data["id"].asInt();
		int type = data["iType"].asInt();
		int enable = data["iEnable"].asInt();
		std::string srois = data["sRoi"].asString();
		std::string url = data["sVideoUrl"].asString();
		std::string location = data["sPosition_name"].asString();
		// 先解析 后创建!
		Json::Reader reader;
		Json::Value  json_roi;
		bool ret = reader.parse(data["sRoi"].asString(), json_roi);
		std::map<int, std::vector<Roi>> rois;
		if(ret){
			for (size_t j = 0; j < json_roi.size(); j++)
			{
				const Json::Value& _json_roi = json_roi[(int)j];
				Roi roi;
				for (size_t k = 0; k < _json_roi["points"].size(); k++)
				{
					const Json::Value& point = _json_roi["points"][(int)k];
					int ix = std::stoi(point["x"].asString());
					int iy = std::stoi(point["y"].asString());
					roi.points.push_back(RoiPoint(ix, iy));
				}
				
				for (size_t k = 0; k < _json_roi["scenarioType"].size(); k++)
				{
					const int& sceneType = _json_roi["scenarioType"][(int)k].asInt();
					auto _it = rois.find(sceneType);
					if (_it != rois.end()){
						_it->second.push_back(roi);	
					}else{
						// TODO 
						rois[sceneType] = std::vector<Roi>{roi};
					}
				}
			}
		}else{
			// 没有ROI直接当作摄像头不启动(现在ROI还包括算法就是了)
			enable = 0;
		}
		// 好了 可以开始走两条路了
		std::shared_ptr<CameraInfo> pCamera = this->GetCameraInfo(cam_id);
		if (pCamera != nullptr)
		{
			// 相机信息比对需要 检查 enable、url、roi
			pCamera->dirty_worker = pCamera->enable != enable ||  pCamera->url != url;
			pCamera->dirty_sync = pCamera->srois != srois || pCamera->enable != enable;
			pCamera->dirty_remove = false;
			// LOG信息
			if(pCamera->dirty_sync || pCamera->dirty_worker){
				LOG_INFO("Camera " << cam_id << " Info change")
			}
		}else{
			// 直接创建新的
			pCamera = std::make_shared<CameraInfo>();
			pCamera->dirty_sync = true;
			pCamera->dirty_worker = true;
			this->m_cameras[cam_id] = pCamera;

			LOG_INFO("Camera New " << cam_id)
		}
		pCamera->id = cam_id;
		pCamera->type = type;
		pCamera->enable = enable;
		pCamera->url = url;
		pCamera->srois = srois;
		pCamera->rois = rois;
		pCamera->location = location;
	}
}

// 拉取任务信息
void WorkerMgr::SyncTaskList(){
	Json::Value root_task;
	if (!HttpMgr::instance().ReqRealTaskList(root_task) || root_task["code"] != 0)
	{
		// 获取不到直接离开
		return;
	}

	for (auto& it:m_tasks){
		if (it.first.first == TaskCate_RealTask){
			it.second->dirty_remove = true;
		}
	}
	
	for (size_t i = 0; i < root_task["data"]["data"].size(); i++)
	{
		const Json::Value& data = root_task["data"]["data"][(int)i];
		int enable = data["iOpen"].asInt();
		int id = data["id"].asInt();
		std::string name = data["sName"].asString();
		std::string stypes = data["sRule"].asString();
		std::string scams = data["sDevice"].asString();
		int itime = data["iTime"].asInt();
		if (!enable) continue;
		
		Json::Reader reader;
		Json::Value  json_tasks;
		bool ret = reader.parse(stypes, json_tasks);
		if(!ret) continue;
		if(json_tasks.size() <= 0) continue;

		Json::Value  json_devices;
		ret = reader.parse(scams, json_devices);
		if (!ret) continue;
		if (json_devices.size() <= 0) continue;

		std::vector<int> tasktypes;
		for (size_t j = 0; j < json_tasks.size(); j++)
		{
			tasktypes.push_back(json_tasks[(int)j].asInt());
		}
		
		std::vector<int> cams;
		for (size_t j = 0; j < json_devices.size(); j++)
		{
			int cam_id = json_devices[(int)j].asInt();
			cams.push_back(cam_id);
		}
		std::vector<std::string> extras;
		extras.push_back(std::to_string(itime));
		// 好了 一样 开始 比较存储的任务信息和新的了
		std::shared_ptr<TaskInfo> pTask = this->GetTaskInfo(TaskCate_RealTask, id);
		if (pTask != nullptr)
		{
			pTask->cams_remove.clear();
			for (size_t k = 0; k < pTask->cams.size(); k++)
			{
				if (std::find(cams.begin(), cams.end(), pTask->cams[k]) == cams.end()){
					pTask->cams_remove.push_back(pTask->cams[k]);
				}
			}

			bool extraDirty = false;
			if (extras.size() != pTask->extras.size()){
				extraDirty = true;
			}else{
				for(size_t l = 0; l < pTask->extras.size(); l++){
					if (pTask->extras[l] != extras[l])
					{
						extraDirty = true;
					}
				}
			}
			pTask->dirty_cams = pTask->stypes != stypes || pTask->scams != scams|| extraDirty;
			pTask->dirty_remove = false;
			if (pTask->dirty_cams)
			{
				LOG_INFO("TaskCate_RealTask " << id << " Info Change")
			}
			
		}else{
			pTask = std::make_shared<TaskInfo>();
			pTask->dirty_cams = true;
			this->m_tasks[std::make_pair(TaskCate_RealTask, id)] = pTask;
			LOG_INFO("TaskCate_RealTask New " << id)
		}
		pTask->id = id;
		pTask->cate = TaskCate_RealTask;
		pTask->stypes = stypes;
		pTask->types = tasktypes;
		pTask->scams = scams;
		pTask->cams = cams;
		pTask->name = name;
		pTask->extras = extras;
	}
}

void WorkerMgr::SyncSkillList(){
	Json::Value root_task;
	if (!HttpMgr::instance().ReqSkillList(root_task)|| root_task["code"] != 0){
		// 获取不到直接离开
		return;
	}

	for (auto &it:m_tasks)
	{
		if (it.first.first == TaskCate_Skill){
			it.second->dirty_remove = true;
		}
	}

	for (size_t i = 0; i < root_task["data"]["data"].size(); i++)
	{
		const Json::Value &data = root_task["data"]["data"][(int)i];
		int enable = data["iStart"].asInt();
		int id = data["id"].asInt();
		std::string name = data["sName"].asString();
		std::string stypes = data["sRule"].asString();
		std::string scams = data["sDevice"].asString();
		std::string sTime = data["iTime"].asString();
		std::string sSustainMinute = data["iSustainMinute"].asString();
		std::string sHandleMinute = data["iHandleMinute"].asString();
		if (!enable) continue;

		Json::Reader reader;

		Json::Value json_devices;
		bool ret = reader.parse(scams, json_devices);
		if (!ret)
			continue;
		if (json_devices.size() <= 0)
			continue;

		std::vector<int> tasktypes;
		tasktypes.push_back(std::stoi(stypes));

		std::vector<int> cams;
		for (size_t j = 0; j < json_devices.size(); j++)
		{
			int cam_id = json_devices[(int)j].asInt();
			cams.push_back(cam_id);
		}

		std::vector<std::string> extras;
		extras.push_back(sTime);
		extras.push_back(sSustainMinute);
		extras.push_back(sHandleMinute);
		// 好了 一样 开始 比较存储的任务信息和新的了
		std::shared_ptr<TaskInfo>
		pTask = this->GetTaskInfo(TaskCate_Skill, id);
		if (pTask != nullptr)
		{
			pTask->cams_remove.clear();
			for (size_t k = 0; k < pTask->cams.size(); k++)
			{
				if (std::find(cams.begin(), cams.end(), pTask->cams[k]) == cams.end())
				{
					pTask->cams_remove.push_back(pTask->cams[k]);
				}
			}
			bool extraDirty = false;
			if (extras.size() != pTask->extras.size()){
				extraDirty = true;
			}else{
				for(size_t l = 0; l < pTask->extras.size(); l++){
					if (pTask->extras[l] != extras[l])
					{
						extraDirty = true;
					}
				}
			}

			pTask->dirty_cams = pTask->stypes != stypes || pTask->scams != scams|| extraDirty;
			pTask->dirty_remove = false;
			if (pTask->dirty_cams)
			{
				LOG_INFO("TaskCate_Skill " << id << " Info Change")
			}
		}
		else
		{
			pTask = std::make_shared<TaskInfo>();
			pTask->dirty_cams = true;
			this->m_tasks[std::make_pair(TaskCate_Skill, id)] = pTask;
			LOG_INFO("TaskCate_Skill New " << id)
		}
		pTask->id = id;
		pTask->cate = TaskCate_Skill;
		pTask->stypes = stypes;
		pTask->types = tasktypes;
		pTask->scams = scams;
		pTask->cams = cams;
		pTask->name = name;
		pTask->extras = extras;
	}
}

// TODO 换个名字吧
void WorkerMgr::DoUpdate(){
	// 疯狂遍历 疯狂循环 疯狂查找
	for (auto& it:this->m_tasks)
	{
		std::shared_ptr<TaskInfo> pTask = it.second;
		TaskCate taskcate = pTask->cate;
		int taskid = pTask->id;
		std::string taskName = pTask->name;
		std::vector<std::string> taskextras = pTask->extras;
		// 如果任务要被移除 则把任务的所有摄像机全部遍历
		if(pTask->dirty_remove){
			pTask->cams_remove = pTask->cams;
		}
		// 遍历需要移除当前任务的摄像机 并将任务从任务列表中删除
		for (size_t i = 0; i < pTask->cams_remove.size(); i++)
		{
			const int& cam_id = pTask->cams_remove[i];
			std::shared_ptr<CameraInfo> pCam = this->GetCameraInfo(cam_id);
			if (pCam == nullptr) continue;
			pCam->tasks.erase(std::remove_if(pCam->tasks.begin(), pCam->tasks.end(), [taskid, taskcate](Task t){ return t.cate == taskcate && t.id == taskid; }),pCam->tasks.end());
			pCam->dirty_sync = true;
			pCam->dirty_worker = pCam->dirty_worker || pCam->tasks.size() == 0;
		}
		pTask->cams_remove.clear();
		// 如果任务的摄像机改变了 则重新设置所有相关摄像机任务
		if (pTask->dirty_cams)
		{
			// 遍历任务的摄像机 并且赋值到对应的列表中 (先删除 然后比对 然后再加入)
			for (size_t i = 0; i < pTask->cams.size(); i++)
			{
				const int& cam_id = pTask->cams[i];
				std::shared_ptr<CameraInfo> pCam = this->GetCameraInfo(cam_id);
				if (pCam == nullptr) continue;
				// 先要把原先的这个任务的相关信息干光
				pCam->tasks.erase(std::remove_if(pCam->tasks.begin(), pCam->tasks.end(), [taskid, taskcate](Task t){ return t.cate == taskcate && t.id == taskid; }), pCam->tasks.end());
				// 额外判断 如果摄像机 中的场景不存在任务的算法 则不加入任务列表 
				// 哪边遍历都一样耗时 绝望
				for (size_t j = 0; j < pTask->types.size(); j++)
				{
					const int& tasktype = pTask->types[j];
					if(pCam->rois.find(tasktype) == pCam->rois.end()) continue;
					Task task;
					task.cate = taskcate;
					task.id = taskid;
					task.name = taskName;
					task.type = tasktype;
					task.extras = taskextras;
					pCam->tasks.push_back(task);
				}
				pCam->dirty_sync = true;
				pCam->dirty_worker = pCam->dirty_worker || pCam->tasks.size() == 0;
			}
			pTask->dirty_cams = false;
		}
	}

	for (auto iter = m_tasks.begin(); iter != m_tasks.end(); )
    {
        if (iter->second->dirty_remove)
        {
			LOG_INFO("Task Remove " << iter->second->id)
            iter = m_tasks.erase(iter);
        }
        else
        {
            ++iter;
        }
    }

	// 处理相机 可能还需要发送消息就是了
	for (auto& it:this->m_cameras)
	{
		std::shared_ptr<CameraInfo> pCamera = it.second;
		if(pCamera->dirty_sync){
			// 只有摄像机是处于开启状态才进行发送!
			if (pCamera->enable && pCamera->tasks.size() > 0)
			{
				std::string msg = Proto::Pack_10000(pCamera);
				MsgSender::instance().Push(msg);
				LOG_INFO(msg);
			}
			pCamera->dirty_sync = false;
		}
		if (pCamera->dirty_worker){
			// 基本上需要重启 只有url改变这个条件 其他情况都是把worker关掉就行了
			if (pCamera->worker != nullptr){
				pCamera->worker->Stop();
			}
			if(pCamera->enable && pCamera->tasks.size() > 0){
				// 重新启动一个worker
				pCamera->worker = std::make_shared<Worker>(pCamera->id, this->m_interval, pCamera->url);
				pCamera->worker->Run();
				LOG_INFO("Camera Start " << pCamera->id)
				this->m_workers.push_back(pCamera->worker);	
			}
			pCamera->dirty_worker = false;
		}
	}

	for (auto iter = m_cameras.begin(); iter != m_cameras.end(); )
    {
        if (iter->second->dirty_remove)
        {
			LOG_INFO("Camera Remove " << iter->second->id)
            iter = m_cameras.erase(iter);
        }
        else
        {
            ++iter;
        }
    }
}

void WorkerMgr::Push(const HttpMsg& msg){
	m_msgs.Push(msg);
}

void WorkerMgr::DoHttpMsg(){
	HttpMsg msg;
	hv::QueryParams _query_params;
	LOG_INFO("DoHttpMsg")
	while(m_msgs.Pop(msg))
	{
		// 有需要处理的HTTP消息就一直进行处理
		// TODO 如果过多 我就封装一层函数指针
		try
		{
			_query_params.clear();
			if (hv::parse_query_params(msg.msg.c_str(), _query_params)){
				LOG_ERROR("DoHttpMsg Parse Failed:" << msg.msg)
				continue;
			}
			switch (msg.type)
			{
				case HttpMsgType_TaskUpload:{
					std::string taskcate = _query_params["cate"];
					std::string camId = _query_params["camId"];
					std::string taskId = _query_params["taskId"];
					std::string taskType = _query_params["taskType"];
					std::string pic = _query_params["pic"];
					std::string time = _query_params["time"];
					int iTaskCate = std::stoi(taskcate);
					int iCamId = std::stoi(camId);
					int iTaskId = std::stoi(taskId);
					int iTaskType = std::stoi(taskType);
					auto pCamera = this->GetCameraInfo(iCamId);
					auto pTask = this->GetTaskInfo(iTaskCate, iTaskId);
					if (pCamera == nullptr)
					{
						LOG_ERROR("DoHttpMsg No Camera : " << iCamId)
						continue;
					}
					if (pTask == nullptr)
					{
						LOG_ERROR("DoHttpMsg No Task : " << iTaskId)
						continue;
					}
					
					std::string taskName = pTask->name;
					std::string location = pCamera->location;
					struct tm *ttime;
					time_t iTime = std::stoi(time);
					ttime = localtime(&iTime);
					char now[64];
					strftime(now, 64, "%Y-%m-%d %H:%M:%S", ttime);

					std::ifstream f(pic.c_str());
					if (!f.good())
					{
						LOG_ERROR("DoHttpMsg pic: " << pic << " not exist!!!!")
						continue;
					}
					LOG_INFO("HttpMsg:" << msg.msg)
					// 上·传·图·片
					switch (iTaskCate)
					{
					case TaskCate_RealTask:{
							HttpMgr::instance().PostUploadTask(iTaskType, location, time, pic, iTaskId, taskName, std::string(now));
						}
						break;
					case TaskCate_Skill:{
							std::string sustaintime = _query_params["sustaintime"];
							HttpMgr::instance().PostUploadAlarm(iTaskId, taskType, sustaintime, time, pic, std::string(now));
						}
						break;
					default:
						break;
					}
					
				}
					break;
				default:
					break;
			}

		}
		catch(const std::exception& e)
		{
			LOG_FATAL(e.what())
		}
		
	}
	LOG_INFO("DoHttpMsg  Finish")
}